package com.jiangyg.mall.core.utils;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.ObjectUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.web.server.ServerWebExchange;

import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.Map;

/**
 * 类描述：常用工具类
 *
 * @author jiangyg
 * @version 4.0
 * @date 2021-10-09
 */
@Slf4j
public class WebUtils {

    /**
     * 功能描述：返回指定数据
     *
     * @param response 响应
     * @param data     数据
     */
    public static void out(HttpServletResponse response, Object data) {
        response.setStatus(HttpStatus.OK.value());
        response.setCharacterEncoding("UTF-8");
        response.setContentType(MediaType.APPLICATION_JSON_VALUE);
        try (final PrintWriter writer = response.getWriter()) {
            writer.print(JsonUtils.toJSONString(data));
        } catch (IOException ex) {
            Logger.error(log, () -> "请求响应出错", ex);
        }
    }

    /**
     * 功能描述：读取请求body的内容
     *
     * @param request 请求
     * @return body值
     */
    public static String readBodyToString(HttpServletRequest request) throws IOException {
        String line;
        final StringBuilder sb = new StringBuilder();
        InputStream in = null;
        BufferedReader reader = null;
        try {
            in = request.getInputStream();
            reader = new BufferedReader(new InputStreamReader(in));
            while ((line = reader.readLine()) != null) {
                sb.append(line);
            }
        } finally {
            if (in != null) {
                in.close();
            }
            if (reader != null) {
                reader.close();
            }
        }
        return sb.toString();
    }

    /**
     * 功能描述：读取请求body的内容
     *
     * @param request 请求
     * @return body值
     */
    public static byte[] readBodyToBytes(HttpServletRequest request) throws IOException {
        final ByteArrayOutputStream bos = new ByteArrayOutputStream();
        try {
            int ch;
            byte[] buffer = new byte[1024];
            ServletInputStream is = request.getInputStream();
            while ((ch = is.read(buffer)) != -1) {
                bos.write(buffer, 0, ch);
            }
            return bos.toByteArray();
        } finally {
            try {
                bos.close();
            } catch (IOException e) {
            }
        }
    }

    /**
     * 功能描述：尝试从请求中读取参数值
     * <p>注意：此方法每个请求尽量只执行一次，否则可能会报错（因为 request.getInputStream() 方法）</p>
     * <p>如果一定要使用的话，请配合 MutilReaderHttpServletRequestWrapper 类使用</p>
     *
     * @param: name 参数名
     * @param: request 请求
     * @return: String 参数值
     */
    public static String attemptReadRequestArgument(String name, HttpServletRequest request) {
        Assert.notNull(request);
        // 1. 尝试从请求中直接读取参数
        String value = request.getParameter(name);
        if (StringUtils.isNotBlank(value)) {
            return value;
        }
        // 2. 尝试从请求头中读取参数
        value = request.getHeader(name);
        if (StringUtils.isNotBlank(value)) {
            return value;
        }
        // 3. 尝试从请求体中读取参数
        try {
            final String body = WebUtils.readBodyToString(request);
            final Map<String, Object> map = JsonUtils.parseMap(body);
            value = ObjectUtils.toString(map.get(name));
        } catch (Exception e) {
        }
        if (StringUtils.isNotBlank(value)) {
            return value;
        }
        return null;
    }

    /**
     * 功能描述：获取请求地址
     *
     * @param: exchange 请求
     * @return: String 请求地址
     */
    public static String getRequestPath(ServerWebExchange exchange) {
        Assert.notNull(exchange);
        return exchange.getRequest().getURI().getPath();
    }

    /**
     * 功能描述：获取请求地址
     *
     * @param: request 请求
     * @return: String 请求地址
     */
    public static String getRequestPath(HttpServletRequest request) {
        Assert.notNull(request);
        return request.getRequestURI();
    }

}
